home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / console / svgatext.3 / svgatext / SVGATextMode-1.3 / XFREE / common_hw / CirrusClk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-30  |  3.8 KB  |  154 lines

  1. /* $XConsortium: CirrusClk.c,v 1.4 95/01/27 14:46:39 kaleb Exp $ */
  2. /* $XFree86: xc/programs/Xserver/hw/xfree86/common_hw/CirrusClk.c,v 3.5 1995/01/28 15:58:08 dawes Exp $ */
  3. /* VCO stability criterion code added by Koen Gadeyne (kmg@barco.be) */
  4.  
  5. /*
  6.  * Programming of the built-in Cirrus clock generator.
  7.  * Harm Hanemaayer <hhanemaa@cs.ruu.nl>
  8.  */
  9.  
  10. #include "compiler.h"
  11. #include "misc.h"
  12. #define NO_OSLIB_PROTOTYPES
  13. #include "xf86_OSlib.h"
  14.  
  15. /* CLOCK_FACTOR is double the osc freq in kHz (osc = 14.31818 MHz) */
  16. #define CLOCK_FACTOR 28636
  17.  
  18. /* stability constraints for internal VCO -- MAX_VCO also determines the maximum Video pixel clock */
  19. #define MIN_VCO CLOCK_FACTOR
  20. #define MAX_VCO 111000
  21.  
  22. /* clock in kHz is (numer * CLOCK_FACTOR / (denom & 0x3E)) >> (denom & 1) */
  23. #define VCOVAL(n, d) \
  24.      ((((n) & 0x7F) * CLOCK_FACTOR / ((d) & 0x3E)) )
  25.  
  26. #define CLOCKVAL(n, d) \
  27.      (VCOVAL(n, d) >> ((d) & 1))
  28.  
  29. #define NU_FIXED_CLOCKS 19
  30.  
  31. typedef struct {
  32.   unsigned char numer;
  33.   unsigned char denom;
  34. } cirrusClockRec;
  35.  
  36. static cirrusClockRec cirrusClockTab[] = {
  37.   { 0x2C, 0x33 },        /* 12.599 */
  38.   { 0x4A, 0x2B },        /* 25.227 */
  39.   { 0x5B, 0x2F },        /* 28.325 */
  40.   { 0x45, 0x30 },         /* 41.164 */
  41.   { 0x7E, 0x33 },        /* 36.082 */
  42.   { 0x42, 0x1F },        /* 31.500 */
  43.   { 0x51, 0x3A },        /* 39.992 */
  44.   { 0x55, 0x36 },        /* 45.076 */
  45.   { 0x65, 0x3A },        /* 49.867 */
  46.   { 0x76, 0x34 },        /* 64.983 */
  47.   { 0x7E, 0x32 },        /* 72.163 */
  48.   { 0x6E, 0x2A },        /* 75.000 */
  49.   { 0x5F, 0x22 },        /* 80.013 */
  50.   { 0x7D, 0x2A },        /* 85.226 */
  51.   { 0x58, 0x1C },        /* 89.998 */
  52.   { 0x49, 0x16 },        /* 95.019 */
  53.   { 0x46, 0x14 },        /* 100.226 */
  54.   { 0x53, 0x16 },        /* 108.035 */
  55.   { 0x5C, 0x18 },        /* 110.248 */
  56. };
  57.  
  58.  
  59. /*
  60.  * This function returns the 7-bit numerator and 6-bit denominator/post-scalar
  61.  * value that corresponds to the closest clock found. If the MCLK is very close
  62.  * to the requested frequency, it sets a flag so that the MCLK can be used
  63.  * as VCLK on chips that support it.
  64.  * If a frequency close to one of the tested clock values is found,
  65.  * use the tested clock since others can be unstable.
  66.  */
  67.  
  68. int CirrusFindClock(freq, num_out, den_out, usemclk_out)
  69.     int freq;
  70.     int *num_out;
  71.     int *den_out;
  72.     int *usemclk_out;
  73. {
  74.     int n, i;
  75.     int num, den;
  76.     int ffreq, mindiff;
  77.     int mclk;
  78.  
  79.     /* Prefer a tested value if it matches within 0.1%. */
  80.     for (i = 0; i < NU_FIXED_CLOCKS; i++) {
  81.         int diff;
  82.         diff = abs(CLOCKVAL(cirrusClockTab[i].numer, 
  83.                   cirrusClockTab[i].denom) - freq);
  84.         if (diff < freq / 1000) {
  85.             num = cirrusClockTab[i].numer;
  86.             den = cirrusClockTab[i].denom;
  87.             goto foundclock;
  88.         }
  89.     }
  90.  
  91.     mindiff = freq; 
  92.     for (n = 0x10; n < 0x7f; n++) {
  93.         int d;
  94.         for (d = 0x14; d < 0x3f; d++) {
  95.             int c, diff;
  96.             /* Avoid combinations that can be unstable. */
  97.             if ((VCOVAL(n, d) < MIN_VCO) || (VCOVAL(n, d) > MAX_VCO))
  98.                 continue;
  99.             c = CLOCKVAL(n, d);
  100.             diff = abs(c - freq);
  101.             if (diff < mindiff) {
  102.                 mindiff = diff;
  103.                 num = n;
  104.                 den = d;
  105.                 ffreq = c;
  106.             }
  107.         }
  108.     }
  109.  
  110. foundclock:
  111.     *num_out = num;
  112.     *den_out = den;
  113.  
  114.     /* Calculate the MCLK. */
  115.     outb(0x3c4, 0x0f);
  116.     mclk = 14318 * (inb(0x3c5) & 0x3f) / 8;
  117.     /*
  118.      * Favour MCLK as VLCK if it matches as good as the found clock,
  119.      * or if it is within 0.2 MHz of the request clock. A VCLK close
  120.      * to MCLK can cause instability.
  121.      */
  122.     if (abs(mclk - freq) <= mindiff + 10 || abs(mclk - freq) <= 200)
  123.         *usemclk_out = TRUE;
  124.     else
  125.         *usemclk_out = FALSE;
  126.  
  127.     return 0;
  128. }
  129.  
  130.  
  131. int CirrusSetClock(freq)
  132.     int freq;
  133. {
  134.     int num, den, usemclk;
  135.     unsigned char tmp;
  136.  
  137.     CirrusFindClock(freq, &num, &den, &usemclk);
  138.  
  139.     /*
  140.      * The 'Use MCLK as VCLK' flag is ignored.
  141.      * This function is only called during start-up if the
  142.      * "probe_clocks" option is specified.
  143.      */
  144.  
  145.     /* Set VLCK3. */
  146.     outb(0x3c4, 0x0e);
  147.     tmp = inb(0x3c5);
  148.     outb(0x3c5, (tmp & 0x80) | num);
  149.     outb(0x3c4, 0x1e);
  150.     tmp = inb(0x3c5);
  151.     outb(0x3c5, (tmp & 0xc0) | den);
  152.     return 0;
  153. }
  154.